import axios from 'axios'
import {Spin, Message} from 'iview'

export default {
    routeRemoteMapByName   : {},//远程权限路由name与路由信息键值对存储，供页面读取远程路由属性
    routeMapByName         : {},//路由name与路由信息键值对存储
    permissionRouteNameList: [],//用户可以访问的路由名称列表
    isGetUserPermission    : false,//是否获取过了权限，每个页面生命周期只获取一次
    requestCommonOptions   : {},//通用请求设置选项，可以通过它设置各个请求的
    urlPre                 : '/api/admin',
    urlList                : {//先关api接口列表
        getUserPowerPage  : '/rbac/power/user-permission',
        getPowerTree      : '/rbac/power/page',
        createPower       : '/rbac/power',
        updatePowerPrefix : '/rbac/power/{id}',// 实际拼接后请求路由 /rbac/power/{id}
        destroyPowerPrefix: '/rbac/power/{id}',// 实际拼接后请求路由 /rbac/power/{id}
        
        getRoleList         : '/rbac/role/page',
        assignRolePermission: '/rbac/role/{id}/assign-role-power-page',
        destroyRole         : '/rbac/role/{id}',
        createRole          : '/rbac/role',
        updateRole          : '/rbac/role/{id}',
        getAllNormalRole    : '/rbac/role',
        
        getUserPage         : '/rbac/user/page',
        getUserRole         : '/rbac/user/{id}/role-ids',
        updateUserRoleAssign: '/rbac/user/{id}/role',
    },
    loadingList            : {},//加载中对象暂存对象
    responseHook           : {},//响应钩子回调函数列表设置，会调用每个函数，参数为响应对象, key => callback,每个key只可以被设置一次函数，后来不覆盖
    loadingHideById(popId) {//加载中的隐藏
        if (popId) {
            //隐藏对应id遮罩
            this.loadingList[popId] && this.loadingList[popId].remove && this.loadingList[popId].remove(() => {});
            delete this.loadingList[popId];
        }
    },
    loadingCreate() {//生成loading
        var loadingPopId               = Date.now() + Math.random().toString();
        this.loadingList[loadingPopId] = Spin.newInstance();
        this.loadingList[loadingPopId].show();
        return loadingPopId;
    },
    getNameComponentMap    : function (routesInfo) {//获取路由name与路由 的简直对，本来供routeComponentAssign使用给新路由赋值 component等信息
        for (let routesIndex in routesInfo) {
            this.routeMapByName[routesInfo[routesIndex].name] = Object.assign({}, routesInfo[routesIndex]);
            
            if (routesInfo[routesIndex].children) {
                this.getNameComponentMap(routesInfo[routesIndex].children)
            }
        }
        
        return this.routeMapByName;
    },
    routeComponentAssign(routesInfo) {//本来是要用来复制组件的，起始现在没有用，左侧导航根据路由的name属性来跳转页面
        for (let routesIndex in routesInfo) {
            const name = routesInfo[routesIndex].name;
            this.permissionRouteNameList.push(name);
            
            //存储远程路由信息，以name为键，供页面读取远程路由属性
            this.routeRemoteMapByName[name] = this._deepClone(routesInfo[routesIndex]);
            
            /*
             *routesInfo[routesIndex]['component'] = this.routeMapByName[name]['component'];
             *routesInfo[routesIndex]['path']      = this.routeMapByName[name]['path'];
             */
            
            if (routesInfo[routesIndex].children) {
                this.routeComponentAssign(routesInfo[routesIndex].children)
            }
        }
        
        return routesInfo;
    },
    removeAuthRouteFromSourceRoutes(routesInfo) {//移除路由中非静态的，以目录为单位，可通过在目录中设置 meta.isStatic = true 来使其不受远程权限路由覆盖
        for (let routesIndex in routesInfo) {
            !routesInfo[routesIndex].meta && (routesInfo[routesIndex].meta = {});
            if (!routesInfo[routesIndex].meta.isStatic) {
                /*
                 *isStatic 值设置一级目录，不要设置在二级
                 *修改本地权限路由，并隐藏，将使用远程配置的路由权限
                 */
                routesInfo[routesIndex].name += '-' + Math.random();
                routesInfo[routesIndex].path += '-' + Math.random();
                routesInfo[routesIndex].meta.hideInMenu = true;//隐藏目录
                continue;
            }
            
            if (routesInfo[routesIndex].children) {
                this.removeAuthRouteFromSourceRoutes(routesInfo[routesIndex].children)
            }
        }
        
        return routesInfo;
    },
    dealRoute(newRoutesInfo, staticRoutesInfo) {//左侧导航生成，通过修改routes来实现
        this.getNameComponentMap(staticRoutesInfo);
        this.permissionRouteNameList = [];
        this.routeComponentAssign(newRoutesInfo);
        this.removeAuthRouteFromSourceRoutes(staticRoutesInfo);
        
        staticRoutesInfo.push(...newRoutesInfo);
        
        //console.log('处理后的导航：', Object.assign([], staticRoutesInfo))
    },
    request(options, successFn, errFn) {//http请求
        const axiosInstance = axios.create();
        
        !options.method && (options.method = 'GET');
        options = Object.assign({}, options, this.requestCommonOptions);
        
        var loadingPopId = this.loadingCreate();//生成加载中的提示
    
        axiosInstance(options).then((response) => {
            this.loadingHideById(loadingPopId);
            this._responseHookTrigger(response);
            successFn && successFn(response);
        }).catch(err => {
            this.loadingHideById(loadingPopId);
            console.log('【rbac】 ajax fail,url:', options.url);
            console.log(err);
            
            Message.error('【rbac】数据请求失败-' + err.toString());
    
            this._responseHookTrigger(err.response);
            errFn && errFn(err);
        });
    },
    setRequestCommonOptions(requestCommonOptions) {// 设置通用请求头部
        this.requestCommonOptions = requestCommonOptions;
        return this;
    },
    setRequestUrlPre(urlPre) {// 设置通用请求前缀
        this.urlPre = urlPre.slice(-1) === '/' ? urlPre.slice(0, -1) : urlPre;
        return this;
    },
    generalUrlWithUrlPreByUri(uri) {//根绝设置的基础url来获取完整url获取uri
        return this.urlPre + uri;
    },
    getUserPermission(
        toRoute,// 去向路由
        routes,// 导航路由
        successFn,// 检测访问权限成功回调
        errFn,// 检测访问权限失败回调
        errResponseFn,//权限请求异常返回回调，用于处理token等过期行为
        requestExtOption,// 请求权限接口额外ajax设置，比如设置请求头部
        url,// 请求接口地址
        successResCheck          = (response) => {// 检测返回结果成功的函数
            return response.status === 200 && response.data.code === 0
        },
        successResRouteDataParse = (response) => {// 解析成功路由的函数
            return response.data.data
        }
    ) {
        const checkRoutePass = () => {
            // 如果获取过远程路由，直接检测，设置了路由中 meta.isStatic 为true的可以直接访问
            if (toRoute.meta.isStatic || this.getPermissionRouteNameList().includes(toRoute.name)) {
                successFn && successFn();
            } else {
                console.log('无权限访问路由', toRoute);
                errFn && errFn();
            }
        };
        
        if (this.isGetUserPermission) {
            checkRoutePass();
        } else {
            // 未获取过远程路由处理
            this.request(
                Object.assign(
                    {
                        url: url || this.generalUrlWithUrlPreByUri(this.urlList.getUserPowerPage),
                    },
                    requestExtOption || {}
                ),
                (response) => {
                    
                    // 默认处理返回结果
                    if (successResCheck(response)) {
                        this.isGetUserPermission = true;// 标记获取远程权限
                        
                        this.dealRoute(successResRouteDataParse(response), routes);// 导航编排
                        
                        // 检测是否有权限访问该路由
                        checkRoutePass();
                        
                    } else {
                        console.log('权限接口返回检测失败', response);
                        Message.error('权限接口返回检测失败');
                        
                        errResponseFn && errResponseFn(response);
                    }
                },
                (err) => {
                    console.log('权限接口请求失败', err, err.response);
                    Message.error('权限接口请求失败', err);
                    errResponseFn && errResponseFn(err.response);
                }
            )
        }
    },
    getPermissionRouteNameList() {
        return this.permissionRouteNameList;
    },
    responseHookPush(hookKey, callback) {//添加响应钩子回调函数
        !this.responseHook[hookKey] && (this.responseHook[hookKey] = callback);
        return this;
    },
    _responseHookTrigger(response) {//触发响应钩子回调函数
        for (let indexHook in this.responseHook) {
            this.responseHook[indexHook](response);
        }
    },
    getRouteRemoteInfoByRouteName(routeName) {//根据路由名称获取远程指定路由信息，页面展示有时候会用到，用于针对改变不同用户的显示
        return this._deepClone(this.routeRemoteMapByName[routeName]);
    },
    _deepClone(source) {//深度拷贝，或者用 lodash.cloneDeep()来实现
        let target;
        if (typeof source === 'object') {
            target = Array.isArray(source) ? [] : {};
            for (let key in source) {
                if (source.hasOwnProperty(key)) {
                    if (typeof source[key] !== 'object') {
                        target[key] = source[key];
                    } else {
                        target[key] = this._deepClone(source[key]);
                    }
                }
            }
        } else {
            target = source
        }
        return target
    },
}
